#include "SkyDome.h"

#include "ShaderManager.h"
#include "SkyDomeFX.h"
#include "VirtualCamera.h"

#include "GeometryGenerator.h"

SkyDome::SkyDome(ID3D11Device* device, LPCWSTR cubeMapFilePath, VirtualCamera* cam)
{
	sphereVertex = NULL;
	sphereIndex = NULL;

	camera = cam;

	sharedShaderManager = ShaderManager::GetInstance();
	effect = sharedShaderManager->ReturnSkyDomeFX();

	CreateBuffers(device, cam->GetFarZ()/2.0f);

	//Load CubeMap.
	HR(D3DX11CreateShaderResourceViewFromFile(device, 
			cubeMapFilePath,
			0, 0, &srv,
			0));
}

SkyDome::~SkyDome()
{
	ReleaseCOM(sphereVertex);
	ReleaseCOM(sphereIndex);

	ReleaseCOM(srv);
}

void SkyDome::Render(ID3D11DeviceContext* context, VirtualCamera* cam)
{
	//Store the current DSS
	ID3D11DepthStencilState* dssStore;
	UINT stencilRefStore;
	context->OMGetDepthStencilState(&dssStore, &stencilRefStore);
	
	//Store the current RS State
	ID3D11RasterizerState* rsStore;
	context->RSGetState(&rsStore);

	// center Sky about eye in world space
	XMMATRIX world = XMMatrixIdentity();
		/*XMMatrixTranslation(
		cam->GetPosition().x, 
		cam->GetPosition().y,
		cam->GetPosition().z);*/

	XMMATRIX wvp = world * cam->GetViewProjection();

	effect->SetCbufferPerObjectData(wvp);
	effect->SetCubeMap(srv);

	UINT stride = sizeof(XMFLOAT3);
	UINT offset = 0;

	context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
	context->IASetInputLayout(effect->ReturnInputLayout());

	context->IASetVertexBuffers(0, 1, &sphereVertex, &stride, &offset);
	context->IASetIndexBuffer(sphereIndex, DXGI_FORMAT_R32_UINT, 0);

	for (unsigned p = 0; p < effect->ReturnActiveTechniqueNumberOfPasses(); p++)
	{
		effect->ApplyActiveTechniqueForPass(p, context);

		context->DrawIndexed(sphereIndexCount, 0, 0);
	}

	//Reset RS and Depth Stencil State.
	context->RSSetState(rsStore);
	context->OMSetDepthStencilState(dssStore, stencilRefStore);

	//release stored states as they increment the reference count
	ReleaseCOM(rsStore);
	ReleaseCOM(dssStore);
}

void SkyDome::CreateBuffers(ID3D11Device* device, float sphereRadius)
{
	//Create a sphere and create D3D buffers. 
	GeometryGenerator::MeshData sphere;
	GeometryGenerator geoGen;
	geoGen.CreateSphere(sphereRadius, 30, 30, sphere);

	std::vector<XMFLOAT3> vertices(sphere.Vertices.size());

	for(size_t i = 0; i < sphere.Vertices.size(); ++i)
	{
		vertices[i] = sphere.Vertices[i].Position;
	}

    D3D11_BUFFER_DESC vbd;
    vbd.Usage = D3D11_USAGE_IMMUTABLE;
	vbd.ByteWidth = sizeof(XMFLOAT3) * vertices.size();
    vbd.BindFlags = D3D11_BIND_VERTEX_BUFFER;
    vbd.CPUAccessFlags = 0;
    vbd.MiscFlags = 0;
	vbd.StructureByteStride = 0;

    D3D11_SUBRESOURCE_DATA vinitData;
    vinitData.pSysMem = &vertices[0];

    HR(device->CreateBuffer(&vbd, &vinitData, &sphereVertex));
	

	sphereIndexCount = sphere.Indices.size();

	D3D11_BUFFER_DESC ibd;
    ibd.Usage = D3D11_USAGE_IMMUTABLE;
    ibd.ByteWidth = sizeof(UINT) * sphereIndexCount;
    ibd.BindFlags = D3D11_BIND_INDEX_BUFFER;
    ibd.CPUAccessFlags = 0;
	ibd.StructureByteStride = 0;
    ibd.MiscFlags = 0;

	std::vector<UINT> indices;
	indices.assign(sphere.Indices.begin(), sphere.Indices.end());

    D3D11_SUBRESOURCE_DATA iinitData;
    iinitData.pSysMem = &indices[0];

    HR(device->CreateBuffer(&ibd, &iinitData, &sphereIndex));
}